home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 676-700 / 681 / term / source.lha / FileBuffer.c < prev    next >
C/C++ Source or Header  |  1992-05-09  |  18KB  |  826 lines

  1. /*
  2. **    $Id: FileBuffer.c,v 1.1 92/04/03 20:41:56 olsen Sta Locker: olsen $
  3. **    $Revision: 1.1 $
  4. **    $Date: 92/04/03 20:41:56 $
  5. **
  6. **    Double-buffered file I/O routines
  7. **
  8. **    Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
  9. **        All Rights Reserved
  10. */
  11.  
  12. #include "termGlobal.h"
  13.  
  14.     /* Size of a file buffer. */
  15.  
  16. #define BUFFER_SIZE    32768
  17.  
  18.     /* The two message signals. */
  19.  
  20. #define    BUFFER_COMMAND    SIGBREAKF_CTRL_E
  21. #define BUFFER_SYNC    SIGBREAKF_CTRL_F
  22.  
  23.     /* Argument types. */
  24.  
  25. enum    {    ARG_NAME,ARG_MODE };
  26. enum    {    ARG_OFFSET,ARG_ORIGIN };
  27.  
  28.     /* Seek offsets. */
  29.  
  30. enum    {    SEEK_SET,SEEK_CURR,SEEK_END };
  31.  
  32.     /* Command codes. */
  33.  
  34. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  35.  
  36.     /* FileBufferServer():
  37.      *
  38.      *    Background process to handle the buffering
  39.      *    of a filehandle, automatically gets invoked
  40.      *    when a file is opened.
  41.      */
  42.  
  43. STATIC VOID __saveds
  44. FileBufferServer()
  45. {
  46.     struct MsgPort    *Port;
  47.     struct Buffer    *Buffer;
  48.     BYTE         Terminated = FALSE,Done,WasFull;
  49.     UBYTE        *String;
  50.     APTR         Data;
  51.     LONG         Length;
  52.     BPTR         SomeLock;
  53.  
  54.         /* Wait for startup message (-> Buffer). */
  55.  
  56.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  57.  
  58.     WaitPort(Port);
  59.  
  60.     Buffer = (struct Buffer *)GetMsg(Port);
  61.  
  62.         /* Open the file and obtain a filehandle. */
  63.  
  64.     String = (UBYTE *)Buffer -> ActionData[ARG_MODE];
  65.  
  66.     Buffer -> WriteAccess = TRUE;
  67.  
  68.         /* Put the message into the list. */
  69.  
  70.     ObtainSemaphore(&DoubleBufferSemaphore);
  71.  
  72.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  73.  
  74.     ReleaseSemaphore(&DoubleBufferSemaphore);
  75.  
  76.         /* Check for the open type. */
  77.  
  78.     switch(String[0])
  79.     {
  80.         case 'r':    if(String[1] == '+')
  81.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  82.                 else
  83.                 {
  84.                     Buffer -> WriteAccess = FALSE;
  85.  
  86.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  87.                 }
  88.  
  89.                 break;
  90.  
  91.         case 'w':    if(String[1] == '+')
  92.                 {
  93.                     if(SomeLock = Lock((UBYTE *)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  94.                     {
  95.                         UnLock(SomeLock);
  96.  
  97.                         DeleteFile((UBYTE *)Buffer -> ActionData[ARG_NAME]);
  98.                     }
  99.  
  100.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  101.                 }
  102.                 else
  103.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  104.  
  105.                 break;
  106.  
  107.         case 'a':    if(SomeLock = Lock((UBYTE *)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  108.                 {
  109.                     UnLock(SomeLock);
  110.  
  111.                     if(Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  112.                     {
  113.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  114.                         {
  115.                             Close(Buffer -> FileHandle);
  116.  
  117.                             Buffer -> FileHandle = NULL;
  118.                         }
  119.                     }
  120.                 }
  121.                 else
  122.                     Buffer -> FileHandle = Open((UBYTE *)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  123.  
  124.                 break;
  125.  
  126.         default:    break;
  127.     }
  128.  
  129.         /* Clear signal bit. */
  130.  
  131.     SetSignal(0,BUFFER_COMMAND);
  132.  
  133.         /* Did the file open? */
  134.  
  135.     if(Buffer -> FileHandle)
  136.     {
  137.         Buffer -> Data        = Buffer -> DataBuffer[0];
  138.         Buffer -> DataCount    = 1;
  139.         Buffer -> Fresh        = TRUE;
  140.  
  141.             /* If not in write mode fill the buffers. */
  142.  
  143.         if(!Buffer -> WriteAccess)
  144.         {
  145.                 /* Fill the first one synchronously. */
  146.  
  147.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  148.             Buffer -> Read        = TRUE;
  149.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  150.  
  151.                 /* Restart caller. */
  152.  
  153.             Signal(Buffer -> Caller,BUFFER_SYNC);
  154.  
  155.                 /* Fill the second buffe asynchronously. */
  156.  
  157.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  158.             Buffer -> RealPosition += Buffer -> Cached;
  159.         }
  160.         else
  161.         {
  162.             UBYTE TempBuffer[256],*Stop;
  163.  
  164.             strcpy(TempBuffer,(UBYTE *)Buffer -> ActionData[ARG_NAME]);
  165.  
  166.             Stop = PathPart(TempBuffer);
  167.  
  168.             *Stop = 0;
  169.  
  170.             if(Buffer -> DirLock = Lock(TempBuffer,ACCESS_READ))
  171.             {
  172.                 if(!Info(Buffer -> DirLock,&Buffer -> InfoData))
  173.                 {
  174.                     UnLock(Buffer -> DirLock);
  175.  
  176.                     Buffer -> DirLock = NULL;
  177.                 }
  178.             }
  179.  
  180.             Signal(Buffer -> Caller,BUFFER_SYNC);
  181.         }
  182.     }
  183.     else
  184.         Terminated = TRUE;
  185.  
  186.         /* Go into loop waiting for commands. */
  187.  
  188.     while(!Terminated)
  189.     {
  190.         Wait(BUFFER_COMMAND);
  191.  
  192.         Done = FALSE;
  193.  
  194.         Buffer -> Result = 0;
  195.  
  196.             /* Take care of each action. */
  197.  
  198.         switch(Buffer -> Action)
  199.         {
  200.                 /* Close the file, flush any dirty
  201.                  * buffers and exit.
  202.                  */
  203.  
  204.             case BUF_CLOSE:    Buffer -> Result = TRUE;
  205.  
  206.                     if(Buffer -> BufPosition && Buffer -> Written)
  207.                     {
  208.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  209.                             Buffer -> Result = FALSE;
  210.                     }
  211.  
  212.                     if(!Close(Buffer -> FileHandle))
  213.                         Buffer -> Result = FALSE;
  214.  
  215.                     if(Buffer -> DirLock)
  216.                         UnLock(Buffer -> DirLock);
  217.  
  218.                     Terminated = TRUE;
  219.  
  220.                     break;
  221.  
  222.                 /* Seek to a specific file position. */
  223.  
  224.             case BUF_SEEK:    Buffer -> Result = 0;
  225.  
  226.                         /* Do nothing if buffer is still
  227.                          * untouched and we are required
  228.                          * to seek back to the beginning
  229.                          * of the file.
  230.                          */
  231.  
  232.                     if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEK_SET)
  233.                     {
  234.                         Signal(Buffer -> Caller,BUFFER_SYNC);
  235.  
  236.                         Done = TRUE;
  237.                     }
  238.                     else
  239.                     {
  240.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  241.                         Buffer -> Read        = FALSE;
  242.  
  243.                         if(Buffer -> BufPosition && Buffer -> Written)
  244.                         {
  245.                             if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  246.                                 Buffer -> Result = -1;
  247.                         }
  248.  
  249.                         if(!Buffer -> Result)
  250.                         {
  251.                             Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  252.  
  253.                             switch(Buffer -> ActionData[ARG_ORIGIN])
  254.                             {
  255.                                 case SEEK_SET:    if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  256.                                             Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  257.                                         else
  258.                                             Buffer -> Result = -1;
  259.  
  260.                                         break;
  261.  
  262.                                 case SEEK_CURR:    if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  263.                                         {
  264.                                             Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  265.                                             Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  266.  
  267.                                             Signal(Buffer -> Caller,BUFFER_SYNC);
  268.  
  269.                                             Done = TRUE;
  270.  
  271.                                             break;
  272.                                         }
  273.  
  274.                                         if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  275.                                             Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  276.                                         else
  277.                                             Buffer -> Result = -1;
  278.  
  279.                                         break;
  280.  
  281.                                 case SEEK_END:    if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  282.                                             Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  283.                                         else
  284.                                             Buffer -> Result = -1;
  285.  
  286.                                         break;
  287.  
  288.                                 default:    Buffer -> Result = -1;
  289.                             }
  290.  
  291.                             Buffer -> ReadBufFull = 0;
  292.  
  293.                             if(Buffer -> Result != -1)
  294.                             {
  295.                                 Buffer -> Data        = Buffer -> DataBuffer[0];
  296.                                 Buffer -> DataCount    = 1;
  297.  
  298.                                 if(!Buffer -> WriteAccess)
  299.                                 {
  300.                                     Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  301.                                     Buffer -> WriteBufFull     = 0;
  302.                                     Buffer -> Read         = TRUE;
  303.                                     Buffer -> RealPosition    += Buffer -> ReadBufFull;
  304.  
  305.                                     if(Buffer -> ReadBufFull)
  306.                                     {
  307.                                         Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  308.  
  309.                                         Buffer -> RealPosition += Buffer -> Cached;
  310.                                     }
  311.                                 }
  312.                             }
  313.                             else
  314.                                 Buffer -> LastActionFailed = TRUE;
  315.                         }
  316.                         else
  317.                             Buffer -> ReadBufFull = 0;
  318.  
  319.                         Buffer -> BufPosition    = 0;
  320.                         Buffer -> Written    = FALSE;
  321.                     }
  322.  
  323.                     break;
  324.  
  325.                 /* Fill the buffer with fresh data. */
  326.  
  327.             case BUF_FILL:    Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  328.                     Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  329.                     Buffer -> WriteBufFull    = 0;
  330.                     Buffer -> BufPosition    = 0;
  331.                     Buffer -> Read        = TRUE;
  332.                     Buffer -> Written    = FALSE;
  333.                     Buffer -> Fresh        = FALSE;
  334.  
  335.                     if(Buffer -> ReadBufFull)
  336.                         WasFull = TRUE;
  337.                     else
  338.                         WasFull = FALSE;
  339.  
  340.                         /* The buffer contents have been
  341.                          * swapped, now wake the caller
  342.                          * up and fill the next buffer
  343.                          * asynchronously.
  344.                          */
  345.  
  346.                     Signal(Buffer -> Caller,BUFFER_SYNC);
  347.  
  348.                     Done = TRUE;
  349.  
  350.                     if(WasFull)
  351.                     {
  352.                         Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  353.  
  354.                         Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  355.  
  356.                         Buffer -> RealPosition += Buffer -> Cached;
  357.  
  358.                         if(!Buffer -> DataLength[Buffer -> DataCount])
  359.                         {
  360.                             if(IoErr())
  361.                                 Buffer -> LastActionFailed = TRUE;
  362.                         }
  363.                     }
  364.  
  365.                     break;
  366.  
  367.                 /* Flush the contents of the buffer to disk. */
  368.  
  369.             case BUF_FLUSH:    if(Buffer -> BufPosition && Buffer -> Written)
  370.                     {
  371.                         Data            = Buffer -> Data;
  372.                         Length            = Buffer -> BufPosition;
  373.  
  374.                         Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  375.                         Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  376.  
  377.                         Buffer -> ReadBufFull    = 0;
  378.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  379.                         Buffer -> BufPosition    = 0;
  380.                         Buffer -> Read        = FALSE;
  381.                         Buffer -> Written    = FALSE;
  382.  
  383.                         Signal(Buffer -> Caller,BUFFER_SYNC);
  384.  
  385.                         Done = TRUE;
  386.  
  387.                         if(Write(Buffer -> FileHandle,Data,Length) != Length)
  388.                             Buffer -> LastActionFailed = TRUE;
  389.                         else
  390.                         {
  391.                             Buffer -> RealPosition += Length;
  392.  
  393.                             if(Buffer -> DirLock)
  394.                             {
  395.                                 if(!Info(Buffer -> DirLock,&Buffer -> InfoData))
  396.                                 {
  397.                                     UnLock(Buffer -> DirLock);
  398.  
  399.                                     Buffer -> DirLock = NULL;
  400.                                 }
  401.                             }
  402.                         }
  403.                     }
  404.                     else
  405.                     {
  406.                         Buffer -> ReadBufFull    = 0;
  407.                         Buffer -> WriteBufFull    = Buffer -> BufLength;
  408.                         Buffer -> BufPosition    = 0;
  409.                         Buffer -> Read        = FALSE;
  410.                         Buffer -> Written    = FALSE;
  411.                     }
  412.  
  413.                     Buffer -> Fresh = FALSE;
  414.  
  415.                     break;
  416.         }
  417.  
  418.             /* Ring back if necessary. */
  419.  
  420.         if(!Done && !Terminated)
  421.             Signal(Buffer -> Caller,BUFFER_SYNC);
  422.     }
  423.  
  424.         /* Remove the message from the list. */
  425.  
  426.     ObtainSemaphore(&DoubleBufferSemaphore);
  427.  
  428.     Remove((struct Node *)Buffer);
  429.  
  430.     ReleaseSemaphore(&DoubleBufferSemaphore);
  431.  
  432.         /* Lock & quit. */
  433.  
  434.     Forbid();
  435.  
  436.     Signal(Buffer -> Caller,BUFFER_SYNC);
  437. }
  438.  
  439.     /* BufferFill(struct Buffer *Buffer):
  440.      *
  441.      *    Fills a given buffer with fresh data.
  442.      */
  443.  
  444. STATIC BYTE __regargs
  445. BufferFill(struct Buffer *Buffer)
  446. {
  447.     if(Buffer -> LastActionFailed)
  448.         return(FALSE);
  449.     else
  450.     {
  451.         if(!Buffer -> ReadBufFull)
  452.         {
  453.             Buffer -> Action = BUF_FILL;
  454.  
  455.             Signal(Buffer -> Child,BUFFER_COMMAND);
  456.  
  457.             Wait(BUFFER_SYNC);
  458.         }
  459.  
  460.         return(TRUE);
  461.     }
  462. }
  463.  
  464.     /* BufferFlush(struct Buffer *Buffer):
  465.      *
  466.      *    Flush the contents of a given buffer to disk.
  467.      */
  468.  
  469. STATIC BYTE __regargs
  470. BufferFlush(struct Buffer *Buffer)
  471. {
  472.     if(Buffer -> LastActionFailed)
  473.         return(FALSE);
  474.     else
  475.     {
  476.         if(Buffer -> BufPosition && Buffer -> Written)
  477.         {
  478.             Buffer -> Action = BUF_FLUSH;
  479.  
  480.             Signal(Buffer -> Child,BUFFER_COMMAND);
  481.  
  482.             Wait(BUFFER_SYNC);
  483.         }
  484.  
  485.         return(TRUE);
  486.     }
  487. }
  488.  
  489.     /* IsValidBuffer(struct Buffer *Buffer):
  490.      *
  491.      *    Scans the double buffered file list for
  492.      *    a valid entry.
  493.      */
  494.  
  495. STATIC BYTE __regargs
  496. IsValidBuffer(struct Buffer *Buffer)
  497. {
  498.     BYTE         GotIt = FALSE;
  499.     struct Node    *Node;
  500.  
  501.     ObtainSemaphore(&DoubleBufferSemaphore);
  502.  
  503.     Node = DoubleBufferList . lh_Head;
  504.  
  505.     while(Node -> ln_Succ)
  506.     {
  507.         if(Buffer == (struct Buffer *)Node)
  508.         {
  509.             GotIt = TRUE;
  510.  
  511.             break;
  512.         }
  513.  
  514.         Node = Node -> ln_Succ;
  515.     }
  516.  
  517.     ReleaseSemaphore(&DoubleBufferSemaphore);
  518.  
  519.     return(GotIt);
  520. }
  521.  
  522.     /* BPrintf():
  523.      *
  524.      *    Prints text into a buffered file.
  525.      */
  526.  
  527. LONG __stdargs
  528. BPrintf(struct Buffer *Buffer,UBYTE *Format,...)
  529. {
  530.     UBYTE    String[256];
  531.     va_list    VarArgs;
  532.  
  533.     va_start(VarArgs,Format);
  534.     VSPrintf(String,Format,VarArgs);
  535.     va_end(VarArgs);
  536.  
  537.     return(BufferWrite(Buffer,String,strlen(String)));
  538. }
  539.  
  540.     /* BufferClose(struct Buffer *Buffer):
  541.      *
  542.      *    Close a buffered filehandle.
  543.      */
  544.  
  545. BYTE __regargs
  546. BufferClose(struct Buffer *Buffer)
  547. {
  548.     if(IsValidBuffer(Buffer))
  549.     {
  550.         BYTE Success;
  551.  
  552.         Buffer -> Action = BUF_CLOSE;
  553.  
  554.         Signal(Buffer -> Child,BUFFER_COMMAND);
  555.  
  556.         Wait(BUFFER_SYNC);
  557.  
  558.         Success = Buffer -> Result;
  559.  
  560.         FreeVec(Buffer);
  561.  
  562.         return(Success);
  563.     }
  564.     else
  565.         return(FALSE);
  566. }
  567.  
  568.     /* BufferOpen(UBYTE *Name,UBYTE *AccessMode):
  569.      *
  570.      *    Open a file for buffered I/O.
  571.      */
  572.  
  573. struct Buffer * __regargs
  574. BufferOpen(UBYTE *Name,UBYTE *AccessMode)
  575. {
  576.     struct Buffer *Buffer;
  577.  
  578.         /* Allocate the buffer data. */
  579.  
  580.     if(Buffer = (struct Buffer *)AllocVec(sizeof(struct Buffer) + BUFFER_SIZE * BUFFER_NUMBER,MEMF_ANY|MEMF_CLEAR))
  581.     {
  582.         struct Process    *Process;
  583.         WORD         i;
  584.  
  585.             /* Set up the first buffer. */
  586.  
  587.         Buffer -> DataBuffer[0] = (UBYTE *)(Buffer + 1);
  588.  
  589.             /* Set up the individual buffers. */
  590.  
  591.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  592.             Buffer -> DataBuffer[i] = &Buffer -> DataBuffer[i - 1][BUFFER_SIZE];
  593.  
  594.         Buffer -> BufLength    = BUFFER_SIZE;
  595.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  596.  
  597.             /* Create the asynchronous file server. */
  598.  
  599.         if(!(Process = CreateNewProcTags(
  600.             NP_Entry,    FileBufferServer,
  601.             NP_Name,    "term file process",
  602.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  603.             NP_StackSize,    8192,
  604.             NP_WindowPtr,    -1,
  605.         TAG_DONE)))
  606.         {
  607.             FreeVec(Buffer);
  608.  
  609.             return(NULL);
  610.         }
  611.  
  612.             /* Set up the message header. */
  613.  
  614.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  615.  
  616.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  617.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  618.  
  619.         Buffer -> Child            = Process;
  620.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  621.  
  622.             /* Send it to the waiting server process. */
  623.  
  624.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  625.  
  626.             /* Wait for ringback. */
  627.  
  628.         Wait(BUFFER_SYNC);
  629.  
  630.             /* Do we have a valid filehandle? */
  631.  
  632.         if(!Buffer -> FileHandle)
  633.         {
  634.             FreeVec(Buffer);
  635.  
  636.             return(NULL);
  637.         }
  638.         else
  639.             return(Buffer);
  640.     }
  641.  
  642.     return(NULL);
  643. }
  644.  
  645.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  646.      *
  647.      *    Move the read/write pointer to a specific position
  648.      *    in a file (not really buffered).
  649.      */
  650.  
  651. BYTE __regargs
  652. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  653. {
  654.     Buffer -> Action            = BUF_SEEK;
  655.     Buffer -> ActionData[ARG_OFFSET]    = Offset;
  656.     Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  657.  
  658.     Signal(Buffer -> Child,BUFFER_COMMAND);
  659.  
  660.     Wait(BUFFER_SYNC);
  661.  
  662.     if(Buffer -> Result == -1)
  663.         return(FALSE);
  664.     else
  665.         return(TRUE);
  666. }
  667.  
  668.     /* BufferRead():
  669.      *
  670.      *    Read data from a file (buffered).
  671.      */
  672.  
  673. LONG __regargs
  674. BufferRead(struct Buffer *Buffer,UBYTE *Destination,LONG Size)
  675. {
  676.     LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  677.     UBYTE    *Data;
  678.  
  679.         /* If there is still data to be written in
  680.          * the buffer, write it.
  681.          */
  682.  
  683.     if(Buffer -> Written)
  684.     {
  685.         if(!BufferFlush(Buffer))
  686.             return(0);
  687.     }
  688.  
  689.         /* Set up for read access. */
  690.  
  691.     BufPosition    = Buffer -> BufPosition;
  692.     ReadBufFull    = Buffer -> ReadBufFull;
  693.     Data        = &Buffer -> Data[BufPosition];
  694.  
  695.         /* Continue until all data has been processed. */
  696.  
  697.     while(Size)
  698.     {
  699.             /* Determine number of bytes to transfer. */
  700.  
  701.         if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  702.         {
  703.             memcpy(Destination,Data,ToCopy);
  704.  
  705.             Size        -= ToCopy;
  706.             BufPosition    += ToCopy;
  707.             ReadBufFull    -= ToCopy;
  708.             Destination    += ToCopy;
  709.             Data        += ToCopy;
  710.             BytesRead    += ToCopy;
  711.         }
  712.         else
  713.         {
  714.                 /* Refill buffer with data. */
  715.  
  716.             Buffer -> BufPosition    = BufPosition;
  717.             Buffer -> ReadBufFull    = ReadBufFull;
  718.  
  719.             if(!BufferFill(Buffer))
  720.                 return(BytesRead);
  721.  
  722.             if(!Buffer -> ReadBufFull)
  723.             {
  724.                 Buffer -> BufPosition = BufPosition;
  725.  
  726.                 return(BytesRead);
  727.             }
  728.  
  729.                 /* Pick up new data. */
  730.  
  731.             BufPosition        = Buffer -> BufPosition;
  732.             ReadBufFull        = Buffer -> ReadBufFull;
  733.             Data            = Buffer -> Data;
  734.         }
  735.     }
  736.  
  737.         /* Install new data. */
  738.  
  739.     Buffer -> BufPosition    = BufPosition;
  740.     Buffer -> ReadBufFull    = ReadBufFull;
  741.  
  742.     return(BytesRead);
  743. }
  744.  
  745.     /* BufferWrite():
  746.      *
  747.      *    Write data to a file (buffered).
  748.      */
  749.  
  750. LONG __regargs
  751. BufferWrite(struct Buffer *Buffer,UBYTE *Source,LONG Size)
  752. {
  753.     LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  754.     UBYTE    *Data;
  755.  
  756.         /* If there is still read data in the buffer,
  757.          * reset the control information.
  758.          */
  759.  
  760.     if(Buffer -> Read)
  761.     {
  762.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  763.         Buffer -> BufPosition    = 0;
  764.         Buffer -> Read        = FALSE;
  765.     }
  766.  
  767.         /* Set up for write access. */
  768.  
  769.     Buffer -> Written = TRUE;
  770.  
  771.     BufPosition    = Buffer -> BufPosition;
  772.     WriteBufFull    = Buffer -> WriteBufFull;
  773.     Data        = &Buffer -> Data[BufPosition];
  774.  
  775.         /* Continue until all data has been processed. */
  776.  
  777.     while(Size)
  778.     {
  779.             /* Determine number of bytes to transfer. */
  780.  
  781.         if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  782.         {
  783.             memcpy(Data,Source,ToCopy);
  784.  
  785.             Size        -= ToCopy;
  786.             BufPosition    += ToCopy;
  787.             WriteBufFull    -= ToCopy;
  788.             Source        += ToCopy;
  789.             Data        += ToCopy;
  790.             BytesWritten    += ToCopy;
  791.         }
  792.         else
  793.         {
  794.                 /* Flush the contents of the
  795.                  * write buffer.
  796.                  */
  797.  
  798.             Buffer -> BufPosition    = BufPosition;
  799.             Buffer -> WriteBufFull    = WriteBufFull;
  800.  
  801.             if(!BufferFlush(Buffer))
  802.                 return(BytesWritten);
  803.  
  804.                 /* Pick up new data. */
  805.  
  806.             BufPosition        = Buffer -> BufPosition;
  807.             WriteBufFull        = Buffer -> WriteBufFull;
  808.             Data            = Buffer -> Data;
  809.  
  810.                 /* Important - or BufferFlush() won't
  811.                  * write the final buffer contents when
  812.                  * the buffered file handle is freed up.
  813.                  */
  814.  
  815.             Buffer -> Written = TRUE;
  816.         }
  817.     }
  818.  
  819.         /* Install new data. */
  820.  
  821.     Buffer -> BufPosition    = BufPosition;
  822.     Buffer -> WriteBufFull    = WriteBufFull;
  823.  
  824.     return(BytesWritten);
  825. }
  826.